package com.yangl.study.beans.factory;

import com.yangl.study.aop.BeanFactoryAware;
import com.yangl.study.beans.BeanDefinition;
import com.yangl.study.BeanReference;
import com.yangl.study.beans.PropertyValue;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * @author yanglei
 * @date 2021-12-02 21:37
 */
public class AutowireCapableBeanFactory extends AbstractBeanFactory {

    /**
     *  bean 属性填充
     * @param bean bean的实例
     * @param beanDefinition bean的定义
     * @throws Exception 异常
     */
    @Override
    protected void applyPropertyValues(Object bean, BeanDefinition beanDefinition) throws Exception {
//        for (PropertyValue propertyValue : beanDefinition.getPropertyValues().getPropertyValues()) {
//            Field declaredField = bean.getClass().getDeclaredField(propertyValue.getName());
//            declaredField.setAccessible(true);
//            Object value = propertyValue.getValue();
//            // 如果属性的类型是 BeanReference 类型 , 则创建 BeanReference 的 bean
//            if (value instanceof BeanReference) {
//                BeanReference beanReference = (BeanReference) value;
//                value = getBean(beanReference.getName());
//            }
//            declaredField.set(bean, value);
//        }
            if (bean instanceof BeanFactoryAware) {
                ((BeanFactoryAware) bean).setBeanFactory(this);
            }
            for (PropertyValue propertyValue : beanDefinition.getPropertyValues().getPropertyValues()) {
                Object value = propertyValue.getValue();
                if (value instanceof BeanReference) {
                    BeanReference beanReference = (BeanReference) value;
                    value = getBean(beanReference.getName());
                }

                try {
                    Method declaredMethod = bean.getClass().getDeclaredMethod(
                            "set" + propertyValue.getName().substring(0, 1).toUpperCase()
                                    + propertyValue.getName().substring(1), value.getClass());
                    declaredMethod.setAccessible(true);

                    declaredMethod.invoke(bean, value);
                } catch (NoSuchMethodException e) {
                    Field declaredField = bean.getClass().getDeclaredField(propertyValue.getName());
                    declaredField.setAccessible(true);
                    declaredField.set(bean, value);
                }
            }
    }
}
